package switchviz.graphic.gauge.tacho.scale;

import javax.media.opengl.GL;

import org.jdom.Element;

import switchviz.graphic.GraphicUtils;
import switchviz.graphic.IGraphicsPanel;
import switchviz.graphic.gauge.IScale;
import switchviz.graphic.gauge.tacho.Tacho3dMultiDataModel.ScaleMode;

public class TachoScale extends IScale
{
	private TachoScaleDataModel _dm = null;
	private TachoScalePanel _scalepanel = null;
	private TachoScalePersistence _nodehandler = null;
	
	private ScaleMode _scalemode;
	private float _min;
	private float _max;
	
	private boolean _enable;
	
	private boolean buildList = true;
	
	public TachoScale(Element root, ScaleMode scalemode, float min, float max, boolean enable)
	{
		_scalemode = scalemode;
		_min = min;
		_max = max;
		_enable = enable;
		
		_nodehandler = new TachoScalePersistence(root);
		
		_dm = _nodehandler.getDataModel();
	}
	
	public void initialize(GL gl)
	{
		buildLists(gl);
	}
	
	private void drawTicks(GL gl, ScaleMode scalemode)
	{
		double fac = Math.PI*(_dm.getAngle()/180)/_dm.getNumbigticks();
		double a,b,c = 1.0 - _dm.getLengthbigticks(), d = 1.0 - _dm.getLengthsmallticks();
		float scalestart = _dm.getScaleStart() + 90;
		
		gl.glBegin (GL.GL_QUADS);
		
		if (_enable)
			gl.glColor4f(_dm.getScaleColor()[0], _dm.getScaleColor()[1], _dm.getScaleColor()[2], 1.0f);
		else
			gl.glColor4f(_dm.getScaleColor()[0], _dm.getScaleColor()[1], _dm.getScaleColor()[2], 0.3f);
		
		for (int i=0; i<=_dm.getNumbigticks(); i++)
		{
			a=(fac * i - _dm.getWidthbigticks()) + ((scalestart / 180) * Math.PI);
			b=(fac * i + _dm.getWidthbigticks()) + ((scalestart / 180) * Math.PI);
			
			gl.glVertex3d (Math.sin(a), Math.cos(a), 0.0);
			gl.glVertex3d (Math.sin(b), Math.cos(b), 0.0);
			gl.glVertex3d (Math.sin(b)*c, Math.cos(b)*c, 0.0);
			gl.glVertex3d (Math.sin(a)*c, Math.cos(a)*c, 0.0);
			
			if (i != _dm.getNumbigticks())
			{
				switch (scalemode)
				{
				case LINEAR:
					double fac2 = ((fac *(i+1)) - (fac*i)) / _dm.getNumsmallticks();
					
					for (int j=1; j<_dm.getNumsmallticks(); j++)
					{
						a=(fac2 * j - _dm.getWidthsmallticks()) + ((scalestart / 180) * Math.PI) + (fac * i);
						b=(fac2 * j + _dm.getWidthsmallticks()) + ((scalestart / 180) * Math.PI) + (fac * i);
						
						gl.glVertex3d (Math.sin(a), Math.cos(a), 0.0);
						gl.glVertex3d (Math.sin(b), Math.cos(b), 0.0);
						gl.glVertex3d (Math.sin(b)*d, Math.cos(b)*d, 0.0);
						gl.glVertex3d (Math.sin(a)*d, Math.cos(a)*d, 0.0);
					}
					break;
				case LOGARITHM:
					double fac3 = ((fac * (i+1)) - (fac * i)) / Math.log10(_dm.getNumsmallticks());
					
					for (int j=1; j<=_dm.getNumsmallticks(); j++)
					{
						a=(fac3 * Math.log10(j) - _dm.getWidthsmallticks()) + ((scalestart / 180) * Math.PI) + (fac * i);
						b=(fac3 * Math.log10(j) + _dm.getWidthsmallticks()) + ((scalestart / 180) * Math.PI) + (fac * i);
						
						gl.glVertex3d (Math.sin(a), Math.cos(a), 0.0);
						gl.glVertex3d (Math.sin(b), Math.cos(b), 0.0);
						gl.glVertex3d (Math.sin(b)*d, Math.cos(b)*d, 0.0);
						gl.glVertex3d (Math.sin(a)*d, Math.cos(a)*d, 0.0);
					}
					break;
				}
			}
		}
		
		gl.glEnd();
		
		if(_dm.getDepth() != 0)
		{
			gl.glBegin (GL.GL_POINTS);
			for (int i=0; i<=_dm.getNumbigticks(); i++)
			{
				for (float j=0; j<_dm.getDepth(); j+=0.2f)
				{						
					gl.glColor4f(_dm.getScaleColor()[0], _dm.getScaleColor()[1], _dm.getScaleColor()[2], 0.4f-(j/_dm.getDepth()/3));
					gl.glVertex3d(Math.sin(fac*i+(scalestart*Math.PI/180)), Math.cos(fac*i+(scalestart*Math.PI/180)), -j);
				}
			}
			gl.glEnd();
		}
	}
	
	public void draw(GL gl)
	{
		if (buildList)
			buildLists(gl);
		
		gl.glCallList(_dm.getList());
	}

	public void setElement(Element node) 
	{
		
	}
	
	private void buildLists(GL gl)
	{
		_dm.setList(gl.glGenLists(1));
		gl.glNewList(_dm.getList(), GL.GL_COMPILE);
		
		gl.glPointSize(1.0f);
		
		double fac = 0;
		
		drawTicks(gl, _scalemode);
		
		fac = Math.PI*_dm.getAngle()/(_dm.getNumbigticks()*180);
		
		float label = _min;
		float labelstep = 1;
		
		switch (_scalemode)
		{
		case LINEAR:
			label = _min;
			labelstep = ((float)(_max-_min)) / _dm.getNumbigticks();
			break;
		case LOGARITHM:
			label = (float) Math.max(_min, Float.MIN_VALUE);
			labelstep = (float) Math.pow(10, (Math.log10(_max)-Math.log10(_min))/_dm.getNumbigticks());
			break;
		}
		
		if (_enable)
			gl.glColor4f(_dm.getScaleColor()[0], _dm.getScaleColor()[1], _dm.getScaleColor()[2], 1.0f);
		else
			gl.glColor4f(_dm.getScaleColor()[0], _dm.getScaleColor()[1], _dm.getScaleColor()[2], 0.3f);
		
		float scalestart = _dm.getScaleStart() + 90;
		
		gl.glBegin(GL.GL_POLYGON);
		gl.glVertex3f((float)Math.sin((scalestart / 180 * Math.PI) - Math.toRadians(5))-0.02f, (float)Math.cos(((scalestart / 180) * Math.PI) - Math.toRadians(5)), 0.0f);
		gl.glVertex3f((float)Math.sin((scalestart / 180 * Math.PI) - Math.toRadians(5))-0.015f, (float)Math.cos(((scalestart / 180) * Math.PI) - Math.toRadians(5))-0.015f, 0.0f);
		gl.glVertex3f((float)Math.sin((scalestart / 180 * Math.PI) - Math.toRadians(5)), (float)Math.cos(((scalestart / 180) * Math.PI) - Math.toRadians(5))-0.02f, 0.0f);
		gl.glVertex3f((float)Math.sin((scalestart / 180 * Math.PI) - Math.toRadians(5))+0.015f, (float)Math.cos(((scalestart / 180) * Math.PI) - Math.toRadians(5))-0.015f, 0.0f);
		gl.glVertex3f((float)Math.sin((scalestart / 180 * Math.PI) - Math.toRadians(5))+0.02f, (float)Math.cos(((scalestart / 180) * Math.PI) - Math.toRadians(5)), 0.0f);
		gl.glVertex3f((float)Math.sin((scalestart / 180 * Math.PI) - Math.toRadians(5))+0.015f, (float)Math.cos(((scalestart / 180) * Math.PI) - Math.toRadians(5))+0.015f, 0.0f);
		gl.glVertex3f((float)Math.sin((scalestart / 180 * Math.PI) - Math.toRadians(5)), (float)Math.cos(((scalestart / 180) * Math.PI) - Math.toRadians(5))+0.02f, 0.0f);
		gl.glVertex3f((float)Math.sin((scalestart / 180 * Math.PI) - Math.toRadians(5))-0.015f, (float)Math.cos(((scalestart / 180) * Math.PI) - Math.toRadians(5))+0.015f, 0.0f);
		gl.glEnd();
		
		
		for (int i=0; i<=_dm.getNumbigticks(); i++)
		{
			
			gl.glPushMatrix();
			
			float sinpart = (float) (Math.sin(fac*i+(scalestart*Math.PI/180))*1.05);
			float cospart = (float) (Math.cos(fac*i+(scalestart*Math.PI/180))*1.1) - 0.05f;
			gl.glTranslatef(sinpart, cospart, 0.0f);
			
			if (sinpart < 0.2f && sinpart > -0.2f)
				GraphicUtils.drawString(gl, 10, GraphicUtils.ALIGN_CENTER, GraphicUtils.FONT_ROMAN, label);
			else if (sinpart >= 0.2f)
				GraphicUtils.drawString(gl, 10, GraphicUtils.ALIGN_LEFT, GraphicUtils.FONT_ROMAN, label);
			else
				GraphicUtils.drawString(gl, 10, GraphicUtils.ALIGN_RIGHT, GraphicUtils.FONT_ROMAN, label);
			
			gl.glPopMatrix();
			
			switch (_scalemode)
			{
			case LINEAR:
				label += labelstep;
				break;
			case LOGARITHM:
				label *= labelstep;
				break;
			}
		}
		gl.glEndList();
		
		buildList = false;
	}
	
	public TachoScaleDataModel getDataModel()
	{
		return _dm;
	}

	public Element getElement() 
	{
		Element node = getSetupPanel().getElement();
		_nodehandler.setElement(node);
		
		_dm = _nodehandler.getDataModel();
		
		buildList = true;
		
		return node;
	}

	public IGraphicsPanel getSetupPanel() 
	{
		if (_scalepanel == null)
			_scalepanel = new TachoScalePanel(_nodehandler.getElement());
		
		return _scalepanel;
	}
}
